<style type="text/css">
    
div.sw{
    position: fixed;
    bottom: 50px;
    left: 50%;
    transform: translateX(-50%);
    color: wheat;
    opacity: 0.7;
}

div.sw:hover{
    opacity: 1;
}

</style>

<template>
    <div id="model"
         @mouseup="control($event,'up')"
         @mousemove="drag($event)"
         @mousedown="control($event,'down')"
         @touchend="control($event,'up')"
         @touchmove="drag($event)"
         @touchstart="control($event,'down')">
        <canvas :width="canvas.width" :height="canvas.height"></canvas>
        <div class="sw">
            <span v-if="!cubeOnly" @click="cubeOnly=true">切换到立方体转动</span>
            <span v-if="cubeOnly" @click="cubeOnly=false">切换到视角转动</span>
        </div>
    </div>
</template>

<script type="text/babel">
const {P, init} = require('../lib/Point');
const {drawPoint:_drawPoint,drawLine: _drawLine} = require('../lib/Draw');
const {Cube} = require('../lib/Cube');
const {Line} = require('../lib/Line');

var canvas = null;
var vm = null;
var drawPoint,drawLine;

const scale = 1 / 50;
const w = 800;
const h = 800;
const focus = P(3000, 0, 0);
const f = 1000;

init({
    canvasWidth: w,
    canvasHeight: h,
    focalLength: f,
    focus: focus
});

const AxL = 3000;
const Screen_distance = 1000;
const Screen_size = 200;

var needSpin = [],Axes,screen,screenCenter,Box,PF,mp,ml;
function calc(p){
    const add = (p1,p2)=>({x:p1.x+p2.x,y:p1.y+p2.y,z:p1.z+p2.z});
    const muti = (p,t)=>({x:p.x*t,y:p.y*t,z:p.z*t});
    const pow = (p,t)=>p.x*t + p.y*t + p.z*t;
    const mix = (o1,o2) => o1.x*o2.x + o1.y*o2.y + o1.z*o2.z; 
    let sc = screenCenter;
    let v_pf = {
        x:PF.x - p.x,
        y:PF.y - p.y,
        z:PF.z - p.z
    };

    //计算r所需常数
    let eqR = mix(sc,sc) - mix(sc,p);
    let eqL = mix(sc,v_pf);

    let r = eqR/eqL;
    //代入r计算目标点
    let offset = muti(v_pf,r);
    let {x:dx,y:dy,z:dz} = add(p,offset);
    return P(dx,dy,dz);
}

var canvasInit = ()=>{
    needSpin = [];

    Axes = [
        new Line(P(AxL,0,0),P(-AxL,0,0)),
        new Line(P(0,AxL,0),P(0,-AxL,0)),
        new Line(P(0,0,AxL),P(0,0,-AxL))
    ];
    screenCenter = P(0,Screen_distance,0);
    screen = [
        P(-Screen_size,Screen_distance,Screen_size),
        P(-Screen_size,Screen_distance,-Screen_size),
        P(Screen_size,Screen_distance,-Screen_size),
        P(Screen_size,Screen_distance,Screen_size)
    ]
    Box = new Cube(200);
    PF = P(0,500,0);

    mp = Box.vertexs.map(p=>calc(p));
    ml = Box.vertexs.map((p,i)=>new Line(p,mp[i]));

    needSpin = needSpin.concat(Axes);
    needSpin = needSpin.concat(Box.vertexs);
    needSpin.push(PF);
    needSpin.push(screenCenter);
    needSpin = needSpin.concat(screen);
    Object.defineProperty(needSpin,'mp',{
        get:function(){
            return mp;
        }
    })
    needSpin.do = function(f){
        needSpin.forEach(f);
        needSpin.mp.forEach(f);
    }
    window.needSpin = needSpin;
}

var render = ()=>{

    canvas.clearRect(0, 0, w, h);
    canvas.fillStyle = "rgb(13,13,13)";
    canvas.fillRect(0, 0, 400, 400);

    Axes.forEach(l=>{
        drawLine(l,'#202020');
    });

    ml.forEach(l=> {
        drawLine(l,'#202020');
    });

    mp.forEach(p=> {
        drawPoint(p,1,'#00c0ff');
    });
    Box.edges.forEach((edge, i)=> {
        drawLine(edge,'#808080');
    });

    drawPoint(PF,2,'#ff80c0');

    canvas.fillStyle = 'rgba(255,255,255,0.1)';
    canvas.beginPath();
    screen.forEach((p,i)=> {
        let ptc = p.toCanvas();
        if(i==0){
            canvas.moveTo(ptc.x,ptc.y);
        }else{
            canvas.lineTo(ptc.x,ptc.y);
        }
    });
    canvas.closePath();
    canvas.fill();

    // canvas.shadowOffsetX = 0;
    // canvas.shadowOffsetY = 0;
    // canvas.shadowColor = 'rgba(255,255,255,0.5)';
    // canvas.shadowBlur = 0;
}

export default {
    data: ()=> ({
        isDrag: false,
        x: 0, y: 0,
        xa: 0, ya: 0,
        isChange: false,
        isPrevent: false,
        percent: 0,
        cubeOnly:false,
        canvas: {
            width: `${w}px`,
            height: `${h}px`
        }
    }),
    methods: {
        spinX: function (a) {
            if(this.cubeOnly){
                Box.vertexs.forEach((what)=> {
                    what.turnX(a);
                });
                mp = mp.map((p,i)=>calc(Box.vertexs[i]));
                ml = Box.vertexs.map((p,i)=>new Line(p,mp[i]));
                return;
            }
            needSpin.do((what)=> {
                what.turnX(a);
            });
        },
        spinY: function (a) {
            if(this.cubeOnly){
                Box.vertexs.forEach((what)=> {
                    what.turnY(a);
                });
                mp = mp.map((p,i)=>calc(Box.vertexs[i]));
                ml = Box.vertexs.map((p,i)=>new Line(p,mp[i]));
                return;
            }
            needSpin.do((what)=> {
                what.turnY(a);
            });
        },
        drag: function ($event) {
            $event.preventDefault();
            if (!this.isDrag || this.isPrevent)return;
            let {abs} = Math;
            let dx = ($event.clientX || $event.touches[0].clientX) - this.x;
            let dy = ($event.clientY || $event.touches[0].clientY) - this.y;
            if (abs(dx) > 0) {
                this.spinX(dx * scale);
            }
            if (abs(dy) > 0) {
                this.spinY(dy * scale);
            }
            this.isChange = true;
            this.x = $event.clientX || $event.touches[0].clientX;
            this.y = $event.clientY || $event.touches[0].clientY;
        },
        control: function ($event, event) {
            if (event == 'down') {
                this.isDrag = true;
                this.x = $event.clientX || $event.touches[0].clientX;
                this.y = $event.clientY || $event.touches[0].clientY;
            } else if (event == 'up') {
                this.isDrag = false;
            }
        }
    },
    ready: function () {
        canvas = [...this.$el.children].filter((n)=> {
            return n.localName == 'canvas'
        })[0].getContext('2d');
        window.canvas = canvas;
        drawLine = _drawLine.bind(this,canvas);
        drawPoint = _drawPoint.bind(this,canvas);
        canvasInit();
        this.isChange = true;

        vm = this;
        vm.spinX(0.3);
        vm.spinY(0.3);

        let Render = ()=> {
            if (!vm.isChange) {
                return window.AnimeRender(Render);
            } else {
                render();
                vm.isChange = false;
                window.AnimeRender(Render);
            }
        };
        window.AnimeRender(Render);
    }
}
</script>
